package org.lgiavedoni.android.franq.util.googe;

import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StringBufferInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.lgiavedoni.android.franq.core.bean.Address;
import org.lgiavedoni.android.franq.core.position.Position;
import org.lgiavedoni.android.franq.core.position.dao.PositionDAO;
import org.lgiavedoni.android.franq.service.log.Logger;
import org.lgiavedoni.android.franq.util.JSONUtil;
import org.lgiavedoni.android.franq.util.network.NetworkUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class GeocodingUtil {

	public static Address getAddress(Position p) {
		try {
			if (p.isUnknowLocation() && !p.isUnknowCell()) {
				setLatLongFromCellId(p);
			}
			if (p.isUnknowLocation()) {
				return null;
			}
			String xml = NetworkUtil.getResponse(new URL("http://maps.googleapis.com/maps/api/geocode/xml?latlng=" + p.getLatitude() + "," + p.getLongitude() + "&sensor=true"));
			if (xml != null)
				return parseXML(xml);
		} catch (Exception ex) {
			Logger.inst.error(ex);
		}
		return null;
	}

	private static Address parseXML(String xml) {
		Address a = new Address();
		try {

			DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
			DocumentBuilder db = dbf.newDocumentBuilder();
			Document doc = db.parse(new StringBufferInputStream(xml));
			doc.getDocumentElement().normalize();
			NodeList nodeLst = doc.getElementsByTagName("address_component");
			for (int i = 0; i < nodeLst.getLength(); i++) {
				Node node = nodeLst.item(i);
				NodeList nodeLst2 = node.getChildNodes();
				for (int j = 0; j < nodeLst2.getLength(); j++) {
					Node child = nodeLst2.item(j);
					// System.out.println(child.getNodeName());
					if ("type".equals(child.getNodeName())) {
						String value = JSONUtil.getTextContent(node.getChildNodes().item(1));
						String text = JSONUtil.getTextContent(child);
						if ("locality".equals(text) && a.getCity() == null)
							a.setCity(value);
						if ("country".equals(text) && a.getCountry() == null)
							a.setCountry(value);
						if ("route".equals(text) && a.getStreet() == null)
							a.setStreet(value);
						if ("street_number".equals(text) && a.getNumber() == null)
							a.setNumber(value);

					}

				}
			}

			return a;
		} catch (Exception e) {
			Logger.inst.error(e);
		}
		return null;
	}

	public static boolean setLatLongFromCellId(Position p) {
		return setLatLongFromCellId(p, p.getCellLocation().getCid(), p.getCellLocation().getLac());
	}

	public static boolean setLatLongFromCellId(Position p, int cellCid, int cellLac) {
		// FIXME: IS NOT WORKINGGGGGGGGG
		try {
			String urlString = "http://www.google.com/glm/mmap";

			// ---open a connection to Google Maps API---
			URL url = new URL(urlString);
			URLConnection conn = url.openConnection();
			HttpURLConnection httpConn = (HttpURLConnection) conn;
			httpConn.setRequestMethod("POST");
			httpConn.setDoOutput(true);
			httpConn.setDoInput(true);
			httpConn.connect();

			// ---write some custom data to Google Maps API---
			OutputStream outputStream = httpConn.getOutputStream();
			WriteData(outputStream, cellCid, cellLac);

			// ---get the response---
			InputStream inputStream = httpConn.getInputStream();
			DataInputStream dataInputStream = new DataInputStream(inputStream);

			BufferedReader br = new BufferedReader(new InputStreamReader(dataInputStream));
			StringBuffer buffer = new StringBuffer();
			String strLine;
			while ((strLine = br.readLine()) != null) {
				buffer.append(strLine + "\n");
			}
			System.out.println(buffer.toString());

			// ---interpret the response obtained---
			dataInputStream.readShort();
			dataInputStream.readByte();
			int code = dataInputStream.readInt();
			if (code == 0) {
				double lat = dataInputStream.readInt() / 1000000D;
				double lng = dataInputStream.readInt() / 1000000D;
				dataInputStream.readInt();
				dataInputStream.readInt();
				dataInputStream.readUTF();

				p.setLatitude(lat);
				p.setLongitude(lng);

				// try to uodate
				if (p.isSaved())
					PositionDAO.inst.update(p);
				return true;
			} else {
				return false;
			}
		} catch (Exception e) {
			Logger.inst.error(e);
			return false;
		}
	}

	private static void WriteData(OutputStream out, int cellID, int lac) throws IOException {
		DataOutputStream dataOutputStream = new DataOutputStream(out);
		dataOutputStream.writeShort(21);
		dataOutputStream.writeLong(0);
		dataOutputStream.writeUTF("en");
		dataOutputStream.writeUTF("Android");
		dataOutputStream.writeUTF("1.0");
		dataOutputStream.writeUTF("Web");
		dataOutputStream.writeByte(27);
		dataOutputStream.writeInt(0);
		dataOutputStream.writeInt(0);
		dataOutputStream.writeInt(3);
		dataOutputStream.writeUTF("");

		dataOutputStream.writeInt(cellID);
		dataOutputStream.writeInt(lac);

		dataOutputStream.writeInt(0);
		dataOutputStream.writeInt(0);
		dataOutputStream.writeInt(0);
		dataOutputStream.writeInt(0);
		dataOutputStream.flush();
	}

	public static void main(String a[]) {
		Logger.inst.start();
		Position p = new Position(52.381454100000006, 4.8572771);
		System.out.println(getAddress(p));

		// Try with cell ID
		p = new Position(0, 0);

		if (setLatLongFromCellId(p, 46742190, 114)) {
			System.out.println(MapsUtil.getURL(p));
		} else {
			System.err.println("ERROR");
		}
	}

}
